package com.hssy.wululuaplan.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hssy.wululuaplan.entity.ClassRemain;
import com.hssy.wululuaplan.entity.PaymentRecord;
import com.hssy.wululuaplan.entity.Student;
import com.hssy.wululuaplan.exception.CustomException;
import com.hssy.wululuaplan.form.PaymentInsertUpdateForm;
import com.hssy.wululuaplan.form.PaymentQueryForm;
import com.hssy.wululuaplan.mapper.ClassRemainMapper;
import com.hssy.wululuaplan.mapper.PaymentRecordMapper;
import com.hssy.wululuaplan.mapper.StudentMapper;
import com.hssy.wululuaplan.service.PaymentRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * <p>
 * 缴费记录 服务实现类
 * </p>
 *
 * @author Mr.Hongtao
 * @since 2024-02-28
 */
@Service
public class PaymentRecordServiceImpl extends ServiceImpl<PaymentRecordMapper, PaymentRecord> implements PaymentRecordService {

    @Resource
    private ClassRemainMapper classRemainMapper;

    @Resource
    private StudentMapper studentMapper;

    @Override
    public List<PaymentRecord> queryFindAll(PaymentQueryForm form) {
        String orderAscColumn = form.getOrderAscColumn();
        if (orderAscColumn != null) {
            switch (orderAscColumn) {
                case "orderNo":
                    return baseMapper.selectList(Wrappers.<PaymentRecord>lambdaQuery()
                            .orderByAsc(PaymentRecord::getOrderNo));
                case "studentId":
                    return baseMapper.selectList(Wrappers.<PaymentRecord>lambdaQuery()
                            .orderByAsc(PaymentRecord::getStudentId));
                case "createTime":
                    return baseMapper.selectList(Wrappers.<PaymentRecord>lambdaQuery()
                            .orderByAsc(PaymentRecord::getCreateTime));
                case "updateTime":
                    return baseMapper.selectList(Wrappers.<PaymentRecord>lambdaQuery()
                            .orderByAsc(PaymentRecord::getUpdateTime));
                case "id":
                    return baseMapper.selectList(Wrappers.<PaymentRecord>lambdaQuery()
                            .orderByAsc(PaymentRecord::getId));
                case "cost":
                    return baseMapper.selectList(Wrappers.<PaymentRecord>lambdaQuery()
                            .orderByAsc(PaymentRecord::getCost));
                default:
                    throw new CustomException(-1, "勾选范围有误，无法查询");
            }
        }else {
            // 不传参数，默认按照学生、订单排序
            return baseMapper.selectList(Wrappers.<PaymentRecord>lambdaQuery()
                    .orderByAsc(PaymentRecord::getStudentId,PaymentRecord::getOrderNo));
        }
    }

    @Override
    @Transactional
    public void create(PaymentInsertUpdateForm form) {
        // 1. 新增缴费记录
        PaymentRecord paymentRecord = new PaymentRecord();
        BeanUtils.copyProperties(form, paymentRecord);
        paymentRecord.setId(null);
        String orderNo = "D" + form.getOrderNoDate() + UUID.randomUUID().toString().substring(0, 3).toUpperCase();
        paymentRecord.setOrderNo(orderNo);
        baseMapper.insert(paymentRecord);

        // 2. 新增/更新课时结余
        Integer studentId = paymentRecord.getStudentId();
        ClassRemain classRemain = classRemainMapper.selectOne(Wrappers.<ClassRemain>lambdaQuery()
                .eq(ClassRemain::getStudentId, studentId)
                .last("limit 1"));
        if (classRemain == null ){
            // 第一次缴费
            ClassRemain entity = new ClassRemain();
            entity.setStudentId(studentId);
            entity.setTotal(paymentRecord.getDuration());
            entity.setRemain(paymentRecord.getDuration());
            if (paymentRecord.getCost().compareTo(BigDecimal.ZERO) == 0) {
                // 包含有免费时长
                entity.setFree(paymentRecord.getDuration());
            }else {
                entity.setFree(0);
            }
            classRemainMapper.insert(entity);
        }else {
            // 非第一次缴费
            // 已有
            Integer total = classRemain.getTotal();
            Integer remain = classRemain.getRemain();
            Integer free = classRemain.getFree();
            // 现有
            classRemain.setTotal(total + paymentRecord.getDuration());
            classRemain.setRemain(remain + paymentRecord.getDuration());
            if (paymentRecord.getCost().compareTo(BigDecimal.ZERO) == 0) {
                // 包含有免费时长
                classRemain.setFree(free + paymentRecord.getDuration());
            }
            classRemainMapper.updateById(classRemain);
        }

    }

    @Override
    @Transactional
    public void edit(PaymentInsertUpdateForm form) {
        // 1. 更新缴费记录
        PaymentRecord paymentRecord = baseMapper.selectById(form.getId());

        if (paymentRecord == null) {
            throw new CustomException(-1000, "当前缴费记录不存在");
        }
        // 更新前的时长数、金额数备用
        Integer durationOrigin = paymentRecord.getDuration();
        BigDecimal costOrigin = paymentRecord.getCost();

        BeanUtils.copyProperties(form, paymentRecord);
        if (!form.getOrderNoDate().equals(paymentRecord.getOrderNo().substring(1,9))) {
            String orderNoNew = "D" + form.getOrderNoDate() + UUID.randomUUID().toString().substring(0, 3).toUpperCase();
            paymentRecord.setOrderNo(orderNoNew);
        }
        baseMapper.updateById(paymentRecord);

        // 2. 更新课时结余
        Integer studentId = paymentRecord.getStudentId();
        ClassRemain classRemain = classRemainMapper.selectOne(Wrappers.<ClassRemain>lambdaQuery()
                .eq(ClassRemain::getStudentId, studentId)
                .last("limit 1"));
        if (classRemain == null) {
            throw new CustomException(-1000, "课时结余记录不存在，请核实是否人为删除了数据库表记录");
        }
        Integer total = classRemain.getTotal();
        Integer remain = classRemain.getRemain();
        Integer free = classRemain.getFree();
        // 剩余记录值 - 此次更新前缴费记录的时长 + 此次更新后缴费记录的时长
        classRemain.setTotal(total - durationOrigin + paymentRecord.getDuration());
        classRemain.setRemain(remain - durationOrigin + paymentRecord.getDuration());
        if (costOrigin.compareTo(BigDecimal.ZERO) == 0) {
            classRemain.setFree(free - durationOrigin);
            if (paymentRecord.getCost().compareTo(BigDecimal.ZERO) == 0) {
                classRemain.setFree(classRemain.getFree() + paymentRecord.getDuration());
            }
        }
        classRemainMapper.updateById(classRemain);

    }

    @Override
    @Transactional
    public void delete(Integer id) {
        // 1. 删除缴费记录
        PaymentRecord paymentRecord = baseMapper.selectById(id);
        baseMapper.deleteById(id);
        // 2. 更新课时结余
        Integer studentId = paymentRecord.getStudentId();
        Integer duration = paymentRecord.getDuration();
        BigDecimal cost = paymentRecord.getCost();
        ClassRemain classRemain = classRemainMapper.selectOne(Wrappers.<ClassRemain>lambdaQuery()
                .eq(ClassRemain::getStudentId, studentId)
                .last("limit 1"));
        if (classRemain == null) {
            throw new CustomException(-1000, "课时结余记录不存在，请核实是否人为删除了数据库表记录");
        }
        Integer remain = classRemain.getRemain();
        Integer free = classRemain.getFree();
        Integer total = classRemain.getTotal();

        classRemain.setTotal(total - duration);
        classRemain.setRemain(remain - duration);
        if (cost.compareTo(BigDecimal.ZERO) == 0) {
            classRemain.setFree(free - duration);
        }
        classRemainMapper.updateById(classRemain);
    }

    @Override
    public List<PaymentRecord> findByStudentId(Integer studentId, String studentName, String expenseItem) {
        if (expenseItem != null && !"".equals(expenseItem)) {
            expenseItem = expenseItem.substring(0,expenseItem.lastIndexOf("(￥"));
        }
        if (studentId == null && studentName != null) {
            Student student = studentMapper.selectOne(Wrappers.<Student>lambdaQuery()
                    .eq(Student::getStudentName, studentName)
                    .last("limit 1"));
            if (student != null) {
                return baseMapper.selectList(Wrappers.<PaymentRecord>lambdaQuery()
                        .eq(PaymentRecord::getStudentId, student.getId())
                        .orderByDesc(PaymentRecord::getOrderNo));
            }else {
                return new ArrayList<>();
            }

        }else {
            if (expenseItem != null && !"".equals(expenseItem)) {
                return baseMapper.selectList(Wrappers.<PaymentRecord>lambdaQuery()
                        .eq(PaymentRecord::getStudentId, studentId)
                        .eq(PaymentRecord::getExpenseItem, expenseItem)
                        .orderByDesc(PaymentRecord::getOrderNo));
            }else {
                return baseMapper.selectList(Wrappers.<PaymentRecord>lambdaQuery()
                        .eq(PaymentRecord::getStudentId, studentId)
                        .orderByDesc(PaymentRecord::getOrderNo));
            }
        }

    }

    @Override
    public List<String> debtPeople() {
        List<ClassRemain> list = classRemainMapper.selectList(Wrappers.<ClassRemain>lambdaQuery()
                .lt(ClassRemain::getRemain, 0)
                .eq(ClassRemain::getDeleteFlag, 0));
        if (list.size() > 0) {
            List<Integer> studentIds = list.stream().map(ClassRemain::getStudentId).collect(Collectors.toList());
            List<Student> studentList = studentMapper.selectList(Wrappers.<Student>lambdaQuery()
                    .in(Student::getId, studentIds)
                    .eq(Student::getDeleteFlag, 0));
            if (studentList.size() > 0) {
                return studentList.stream().map(Student::getStudentName).collect(Collectors.toList());
            }
            return new ArrayList<>();
        }else {
            return new ArrayList<>();
        }
    }
}
